﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Zhy.DigitaPlatform.Common.Base;
using Zhy.DigitaPlatform.DeviceAccess.Base;
using Zhy.DigitaPlatform.DeviceAccess.Transfer;
using Zhy.DigitaPlatform.Entities;

namespace Zhy.DigitaPlatform.DeviceAccess.Execute
{
    /// <summary>
    /// Modbus通讯基类
    /// </summary>
    public abstract class ExecuteObject
    {
        /// <summary>
        /// 动态配置字节
        /// </summary>
        public EndianType EndianType { get; set; } = EndianType.ABCD;
        /// <summary>
        /// 设备的组件通讯属性集合
        /// </summary>
        internal List<DevicePropItemEntity> Props { get; set; }
        /// <summary>
        /// 通讯对象
        /// </summary>
        internal TransferObject TransferObject { get; set; }

        /// <summary>
        /// 查找共用的通信对象
        /// </summary>
        /// <param name="props">设备的组件通讯属性集合</param>
        /// <param name="tos">通讯对象集合</param>
        /// <param name="conditions">要连接的通讯对象名称：比如串口名称或者IP地址</param>
        /// <param name="protocol">通讯对象名称：后面通过反射实例化通讯对象</param>
        /// <returns></returns>
        internal Result Match(List<DevicePropItemEntity> props, List<TransferObject> tos, List<string> conditions, string protocol)
        {
            Result result = new Result(); // 实例化通讯结果对象

            try
            {
                this.Props = props;
                // 获取大小端属性-字节序
                var prop = props.FirstOrDefault(p => p.PropName == "Endian");
                if (prop != null)
                    this.EndianType = (EndianType)Enum.Parse(typeof(EndianType), prop.PropValue);

                // 从tos列表中找到PortName值一样的对象 - 用于判断通讯对象是否已创建
                this.TransferObject = tos.FirstOrDefault(
                    to =>
                    to.GetType().Name == protocol &&
                    conditions.All(s => to.Conditions.Any(c => c == s))  // 匹配两上集合是否一致
                    );

                if (this.TransferObject == null) // 如果通讯对象没创建则新建
                {
                    // 通过反射实例化通讯对象
                    Type type = this.GetType().Assembly.GetType("Zhy.DigitaPlatform.DeviceAccess.Transfer." + protocol);
                    this.TransferObject = (TransferObject)Activator.CreateInstance(type); // 实例化通讯对象

                    this.TransferObject.Conditions = conditions;
                    tos.Add(this.TransferObject);

                    // 初始化相关属性   
                    Result result_config = this.TransferObject.Config(props); // 获取通讯配置属性
                    if (!result_config.Status)
                        return result_config;
                }
            }
            catch (Exception ex)
            {
                result.Status = false;
                result.Message = ex.Message;
            }
            return result;
        }

        /// <summary>
        /// 查找共用的通信对象
        /// </summary>
        /// <param name="props">设备的组件通讯属性集合</param>
        /// <param name="tos">通讯对象集合</param>
        /// <returns></returns>
        internal virtual Result Match(List<DevicePropItemEntity> props, List<TransferObject> tos) 
            => new Result(); // 相当于设置返回参数

        /// <summary>
        /// 连接方法
        /// </summary>
        public virtual void Connect() { }
        /// <summary>
        /// 读取报文数据
        /// </summary>
        /// <param name="variables"></param>
        /// <returns></returns>
        public virtual Result Read(List<CommAddress> variables) => new Result();
        /// <summary>
        /// 异步读取数据
        /// </summary>
        public virtual void ReadAsync() { }
        /// <summary>
        /// 写入数据
        /// </summary>
        public virtual void Write() { }
        /// <summary>
        /// 异步写入数据
        /// </summary>
        public virtual void WriteAsync() { }
        /// <summary>
        /// 资源释放
        /// </summary>
        public virtual Result Dispose()
        {
            if (this.TransferObject == null) return new Result();
            try
            {
                this.TransferObject?.Close();
                return new Result();
            }
            catch (Exception ex)
            {
                return new Result(false, ex.Message);
            }
        }

        /// <summary>
        /// 将要获取的Modbus-根据功能码进行分组
        /// 将相同的功能码整理成一次访问，使用这种方式减少与硬件的设备的通讯次数。
        /// </summary>
        /// <param name="variables"></param>
        /// <returns></returns>
        public virtual Result<List<CommAddress>> GroupAddress(List<VariableProperty> variables)
        {
            return new Result<List<CommAddress>>(false, "");
        }

        /// <summary>
        /// 表示将一个数据字节进行指定字节序的调整
        /// </summary>
        /// <param name="bytes">接收待转换的设备中返回的字节数组</param>
        /// <returns>返回调整完成的字节数组</returns>
        public List<byte> SwitchEndianType(List<byte> bytes)
        {
            // 不管是什么字节序，这个Switch里返回的是ABCD这个顺序
            List<byte> temp = new List<byte>();
            switch (EndianType)  // alt+enter
            {
                case EndianType.ABCD:
                    temp = bytes;
                    break;
                case EndianType.DCBA:
                    for (int i = bytes.Count - 1; i >= 0; i--)
                    {
                        temp.Add(bytes[i]);
                    }
                    break;
                case EndianType.CDAB:
                    temp = new List<byte> { bytes[2], bytes[3], bytes[0], bytes[1] };
                    break;
                case EndianType.BADC:
                    temp = new List<byte> { bytes[1], bytes[0], bytes[3], bytes[2] };
                    break;
            }
            if (BitConverter.IsLittleEndian)
                temp.Reverse();

            return temp;
        }
    }
}
